﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Proggy.Web.Cms.PropertyTypes;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using Proggy.Web.Cms.ContentModel;
using System.Reflection;

namespace Proggy.Web.Cms.Extensions.Html
{
    /// <summary>
    /// Html editor extensions
    /// </summary>
    public static class ProggyEditorExtensions
    {
        /// <summary>
        /// Returns an editor for a property type
        /// </summary>
        /// <param name="html"></param>
        /// <param name="propt"></param>
        /// <returns></returns>
        public static void RenderContentModelPropertyEditor(this HtmlHelper html, AvailablePropertyType propt, IContentModelBase parentModel)
        {
            // find model
            var model = parentModel;

            // get type of model
            var modelType = model.GetType();

            // get properties
            var allPropInfos = modelType.GetProperties();

            // find corresponding property in model
            var correspondingPropInfo = allPropInfos.Single(x => x.Name == propt.PropertyName);

            // get prop type
            var correspondingPropType = propt.PropertyType;

            // get corresponing property with value
            var correspondingPropWithValue = correspondingPropInfo.GetValue(model, null);

            // check null
            if (correspondingPropWithValue == null)
            {
                // create new
                correspondingPropWithValue = Activator.CreateInstance(correspondingPropType);
            }

            // check if property type inherits from configurable
            if (propt.RequiresConfiguration)
            {

                // get base config object
                var baseConfigProp = allPropInfos.SingleOrDefault(x => x.Name == propt.PropertyName + "ConfigObject");

                // start type of config prop
                Type baseConfigPropType = null;

                // check
                if (baseConfigProp != null) {
                    baseConfigPropType = baseConfigProp.PropertyType;
                }

                // check
                if (baseConfigProp == null || baseConfigPropType != propt.PropertyTypeAttribute.RequiredConfigObjectType)
                {
                    throw new Exception(
                        string.Format(
                            "Property \"{0}\" of type \"{1}\" requires fully instantiated corresponding read only property named \"{0}ConfigObject\" of type \"{2}\"",
                            propt.PropertyName, propt.PropertyType.ToString(), propt.PropertyTypeAttribute.RequiredConfigObjectType.ToString()
                        )
                        );
                }

                // get property with value
                var baseConfigObj = baseConfigProp.GetValue(model, null);

                // check null
                if (baseConfigObj == null)
                {
                    throw new Exception(
                        string.Format(
                            "Property \"{0}\" of type \"{1}\" requires fully instantiated corresponding read only property named \"{0}ConfigObject\" of type \"{2}\"",
                            propt.PropertyName, propt.PropertyType.ToString(), propt.PropertyTypeAttribute.RequiredConfigObjectType.ToString()
                        ));
                }

                ((ConfigurablePropertyTypeBase)correspondingPropWithValue).BaseConfigObject = baseConfigObj;
                ((ConfigurablePropertyTypeBase)correspondingPropWithValue).OnAfterConfigObjectSetInBackEnd();
            }


            // set name start
            ((PropertyTypeBase)correspondingPropWithValue).PropertyNameStart = propt.PropertyName;

            // finally, render
            RenderPartialExtensions.RenderPartial(
                html,
                propt.PropertyTypeAttribute.View,
                correspondingPropWithValue);

            #region v1

            //// get model
            //var model = (IContentModelBase)html.ViewContext.ViewData.Model;

            //// get model type
            //var type = model.GetType();

            //// get props
            //var props = type.GetProperties();

            //// get property
            //var property = props.Single(x => x.Name == propt.PropertyName);
            //var propertyValue = property.GetValue(model, null);

            //// check value
            //if (propertyValue == null)
            //{
            //    propertyValue = Activator.CreateInstance(property.PropertyType);
            //}

            //// get config
            //object configObjectValue = null;
            //PropertyInfo configObjectProperty = null;
            //if (propt.HasConfigObject)
            //{
            //    configObjectProperty = props.Single(x => x.Name == propt.ConfigObjectPropertyName);
            //    configObjectValue = property.GetValue(model, null);
            //}

            //// check
            //if (configObjectValue != null && configObjectValue.GetType() != propt.PropertyTypeAttribute.ConfigObjectType) {
            //    throw new Exception(
            //        string.Format("The property {0} of type {1} requires a config object of type {2}",
            //        propt.PropertyName, propt.PropertyType.ToString(), propt.PropertyTypeAttribute.ConfigObjectType.ToString()));
            //}

            //// render
            //RenderPartialExtensions.RenderPartial(
            //    html,
            //    propt.PropertyTypeAttribute.View,
            //    propertyValue,
            //    new ViewDataDictionary { { "ConfigObject", new ProggyEditorPartialConfigObject(propt.PropertyName, configObjectValue) } }
            //);

            #endregion
        }
    }
}
